﻿using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;

namespace Lepton_Practical_MVVM_6_1.Views {

    public static class CommandBehavior {

        // UI,Handler List
        private static Dictionary<UIElement, RoutedEventHandler> handlers = new Dictionary<UIElement, RoutedEventHandler>();

        #region Command Property

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached(
                "Command",
                typeof(ICommand),
                typeof(CommandBehavior),
                new FrameworkPropertyMetadata() {
                    DefaultValue = null,
                    PropertyChangedCallback = new PropertyChangedCallback(OnCommandPropertyChanged)
                }
            );
        public static ICommand GetCommand(UIElement obj) {
            return (ICommand)obj.GetValue(CommandProperty);
        }
        public static void SetCommand(UIElement obj, ICommand value) {
            obj.SetValue(CommandProperty, value);
        }

        #endregion

        #region Event Property
        public static readonly DependencyProperty EventProperty =
            DependencyProperty.RegisterAttached(
                "Event",
                typeof(RoutedEvent),
                typeof(CommandBehavior),
                new FrameworkPropertyMetadata() {
                    DefaultValue = null,
                    PropertyChangedCallback = new PropertyChangedCallback(OnEventPropertyChanged)
                }
            );
        public static RoutedEvent GetEvent(DependencyObject obj) {
            return (RoutedEvent)obj.GetValue(EventProperty);
        }
        public static void SetEvent(DependencyObject obj, RoutedEvent value) {
            obj.SetValue(EventProperty, value);
        }

        #endregion

        #region CallBacks

        private static void OnCommandPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) {
            UIElement element = obj as UIElement;
            ICommand oldCommand = args.OldValue as ICommand;
            ICommand newCommand = args.NewValue as ICommand;
            RoutedEvent routedEvent = element.GetValue(EventProperty) as RoutedEvent;

            Detach(element, routedEvent, oldCommand);
            Attach(element, routedEvent, newCommand);
        }

        private static void OnEventPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) {
            UIElement element = obj as UIElement;
            RoutedEvent oldEvent = args.OldValue as RoutedEvent;
            RoutedEvent newEvent = args.NewValue as RoutedEvent;
            ICommand command = element.GetValue(CommandProperty) as ICommand;

            Detach(element, oldEvent, command);
            Attach(element, newEvent, command);
        }

        #endregion

        private static void Attach(UIElement element, RoutedEvent Event, ICommand command) {
            if (Event != null && element != null && command != null) {
                RoutedEventHandler InvokeCommandHandler = new RoutedEventHandler(delegate {
                    command.Execute(null);
                });
                handlers.Add(element, InvokeCommandHandler);
                element.AddHandler(Event, InvokeCommandHandler);
            }
        }

        private static void Detach(UIElement element, RoutedEvent Event, ICommand command) {
            if (Event != null && element != null && command != null) {
                RoutedEventHandler handler = handlers[element];
                if (handler != null) {
                    element.RemoveHandler(Event, handler);
                    handlers.Remove(element);
                }
            }
        }
    }
}